#include "User.h"
#include "BusinessLogic.h"

CUser::CUser(int sock)
{
	m_bCustomer = true;
	m_bAuthSuccess = false;
	m_pMsgSplitter = CreateMsgSplitter();
	m_event = CreateEvent(NULL, FALSE, FALSE, NULL);
	m_sock = sock;
}

CUser::~CUser(void)
{
	Stop();
	DestroyMsgSplitter(m_pMsgSplitter);
}

void CUser::Start()
{
	m_hThrd = (HANDLE)_beginthread(CUser::worker, 0, this);
	WaitForSingleObject(m_event, INFINITE);
}

void CUser::Stop()
{
	if (IsStopped())
		return;

	closesocket(m_sock);
	WaitForSingleObject(m_hThrd, INFINITE);
	CloseHandle(m_hThrd);
	m_hThrd = NULL;
	CloseHandle(m_event);
}

void CUser::SendMsg(MSG_BASE* pMsg)
{
	if (NULL == pMsg) return;

	SendMessage(pMsg, m_sock);
}

void CUser::worker(void* pParam)
{
	CUser* pUser = (CUser*)pParam;
	SetEvent(pUser->m_event);

	while (true)
	{
		int nRecv = 0;
		if ((nRecv = pUser->m_pMsgSplitter->RecvData(pUser->m_sock)) <= 0)
			break;

		MSG_BASE* pMsg = NULL;
		while (true)
		{
			MSG_BASE* pMsg = pUser->m_pMsgSplitter->ExtractMsg();
			if (NULL == pMsg)
				break;

			pUser->processMsg(pMsg);
			DeleteMsg(pMsg);
		}
	}
}

void CUser::processMsg(MSG_BASE* pMsg)
{
	if (NULL == pMsg)
		return;

	//Handle register or authentication message
	if (pMsg->nMsgType == MSGTYPE_USER_REG)
		return onMsgUserReg((MSG_USER_REG&)(*pMsg));

	if (pMsg->nMsgType == MSGTYPE_USER_AUTH)
		return onMsgUserAuth((MSG_USER_AUTH&)(*pMsg));

	if (pMsg->nMsgType == MSGTYPE_AIRLINE_AUTH)
		return onMsgAirLineAuth((MSG_AIRLINE_AUTH&)(*pMsg));

	if (!m_bAuthSuccess)
		return;

	switch(pMsg->nMsgType)
	{
	case MSGTYPE_ROUTE_SEL:
		onMsgRouteSel((MSG_ROUTE_SEL&)(*pMsg));
		break;

	case MSGTYPE_CUST_RESERV:
		onMsgCusReserve((MSG_CUST_RESERV&)(*pMsg));
		break;

	case MSGTYPE_VIEW_ORDER_REQUEST:
		onMsgViewOrder((MSG_VIEW_ORDER_REQUEST&)(*pMsg));
		break;

	case MSGTYPE_CANCEL_ORDER:
		onMsgCancelOrder((MSG_CANCEL_ORDER&)(*pMsg));
		break;

	case MSGTYPE_AIRLINE_ADDROUTE:
		onMsgAirLineAddRoute((MSG_AIRLINE_ADDROUTE&)(*pMsg));
		break;

	case MSGTYPE_VIEW_ROUTES:
		onMsgViewRoute();
		break;

	default:
		break;
	}
}

void CUser::onMsgUserReg(MSG_USER_REG& msg)
{
	bool bSuccess = CBusinessLogic::GetInstance().UserRegister(msg.szAccount, msg.szPasswd);

	MSG_SUCCESS_REPLY repMsg;
	repMsg.bSuccess = bSuccess;
	m_bAuthSuccess = bSuccess;
	strcpy(repMsg.szReason, "Register failed");
	strcpy(m_szAccount, msg.szAccount);

	SendMsg(&repMsg);
}

void CUser::onMsgUserAuth(MSG_USER_AUTH& msg)
{
	bool bSuccess = CBusinessLogic::GetInstance().UserAuth(msg.szAccount, msg.szPasswd);

	if (bSuccess)
		m_bCustomer = true;

	MSG_SUCCESS_REPLY repMsg;
	repMsg.bSuccess = bSuccess;
	m_bAuthSuccess = bSuccess;
	strcpy(repMsg.szReason, "Authentication failed");
	strcpy(m_szAccount, msg.szAccount);

	SendMsg(&repMsg);
}

void CUser::onMsgRouteSel(MSG_ROUTE_SEL& msg)
{
	vector<ROUT_ENTRY> vecRes;
	CBusinessLogic::GetInstance().UserSelRoute(msg, vecRes);

	int nSize = MSG_ROUTE_REPLY::CalculateMsgSize(vecRes.size());
	if (0 == nSize) return;

	char* pMem = new char[nSize];
	MSG_ROUTE_REPLY* pMsg = (MSG_ROUTE_REPLY*)pMem;
	pMsg->Initialize(nSize, vecRes.size());

	int i = 0;
	for (vector<ROUT_ENTRY>::iterator it = vecRes.begin();
		it != vecRes.end(); it++)
		pMsg->entries[i++] = *it;

	SendMsg(pMsg);

	delete []pMem;
}

void CUser::onMsgCusReserve(MSG_CUST_RESERV& msg)
{
	MSG_SUCCESS_REPLY repMsg;
	repMsg.bSuccess = CBusinessLogic::GetInstance().UserOrderRoute
		(m_szAccount, msg.nRouteNum, msg.nCabTp);

	SendMsg(&repMsg);
}

void CUser::onMsgViewOrder(MSG_VIEW_ORDER_REQUEST& msg)
{
	vector<ORDER_ENTRY> vecRes;
	CBusinessLogic::GetInstance().ViewOrders(m_bCustomer, m_szAccount, vecRes);

	int nLen = MSG_VIEW_ORDER_CONTENT::CalculateMsgSize(vecRes.size());
	if (nLen <= 0) return;

	char* pMem = new char[nLen];
	MSG_VIEW_ORDER_CONTENT* pMsg = (MSG_VIEW_ORDER_CONTENT*)pMem;
	pMsg->Initialize(nLen, vecRes.size());

	int i = 0;
	for (vector<ORDER_ENTRY>::iterator it = vecRes.begin();
		it != vecRes.end(); it++)
		pMsg->orders[i++] = *it;

	SendMsg(pMsg);
	delete []pMem;
}

void CUser::onMsgCancelOrder(MSG_CANCEL_ORDER& msg)
{
	MSG_SUCCESS_REPLY repMsg;
	repMsg.bSuccess = CBusinessLogic::GetInstance().CancelAnOrder
		(m_bCustomer, m_szAccount, msg.nReservId);
	SendMsg(&repMsg);
}

void CUser::onMsgAirLineAuth(MSG_AIRLINE_AUTH& msg)
{
	bool bSuccess = CBusinessLogic::GetInstance().AirLineAuth(msg.szAccount, msg.szPasswd);

	if (bSuccess)
		m_bCustomer = false;

	MSG_SUCCESS_REPLY repMsg;
	repMsg.bSuccess = bSuccess;
	m_bAuthSuccess = bSuccess;
	strcpy(repMsg.szReason, "Authentication failed");
	strcpy(m_szAccount, msg.szAccount);

	SendMsg(&repMsg);
}

void CUser::onMsgAirLineAddRoute(MSG_AIRLINE_ADDROUTE& msg)
{
	if (m_bCustomer != 0)
		return;

	MSG_SUCCESS_REPLY repMsg;
	strcpy(msg.entry.strAirLine, m_szAccount);
	repMsg.bSuccess = CBusinessLogic::GetInstance().AddRoute(msg.entry);
	SendMsg(&repMsg);
}

void CUser::onMsgViewRoute()
{
	if (m_bCustomer) return;

	vector<ROUT_ENTRY> vecRes;
	CBusinessLogic::GetInstance().ViewRoutes(m_szAccount, vecRes);

	int nSize = MSG_ROUTE_REPLY::CalculateMsgSize(vecRes.size());
	if (0 == nSize) return;

	char* pMem = new char[nSize];
	MSG_ROUTE_REPLY* pMsg = (MSG_ROUTE_REPLY*)pMem;
	pMsg->Initialize(nSize, vecRes.size());

	int i = 0;
	for (vector<ROUT_ENTRY>::iterator it = vecRes.begin();
		it != vecRes.end(); it++)
		pMsg->entries[i++] = *it;

	SendMsg(pMsg);

	delete []pMem;
}